/**
 * 
 */
package fr.gfi.agraf.service.impl;

import java.util.List;
import java.util.Set;

import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;

import fr.gfi.agraf.exception.AgrafException;
import fr.gfi.agraf.persistence.dao.IProfilDAO;
import fr.gfi.agraf.persistence.dao.IUtilisateurDAO;
import fr.gfi.agraf.persistence.entity.Droit;
import fr.gfi.agraf.persistence.entity.Profil;
import fr.gfi.agraf.persistence.entity.Utilisateur;
import fr.gfi.agraf.service.IProfilService;
import fr.gfi.agraf.service.mapper.ComposantMapper;
import fr.gfi.agraf.service.mapper.ProfilMapper;
import fr.gfi.agraf.vue.bean.ProfilDTO;

/**
 * @author Zakaria
 *
 */
@Service("ProfilService")
@Transactional(propagation = Propagation.REQUIRED)
public class ProfilService implements IProfilService {

	private static final String ERREUR_PROFIL_UTILISATEUR_ATTACHED = "erreur.profil.utilisateur.attached";
	private static final String ERREUR_PROFIL_LIBELLE_EXIST = "erreur.profil.libelleExist";
	private static final String ERREUR_PROFIL_NOTFOUND = "erreur.profil.notfound";
	@Autowired
	private IProfilDAO profilDAO;
	@Autowired
	private IUtilisateurDAO utilisateurDAO;

	/*
	 * (non-Javadoc)
	 * 
	 * @see fr.gfi.agraf.service.IProfilService#getProfilById()
	 */
	public ProfilDTO getProfilById(final Long id) throws AgrafException {
		final Profil profil = profilDAO.read(id);
		if (profil == null) {
			throw new AgrafException(ERREUR_PROFIL_NOTFOUND);
		}
		return ProfilMapper.entityToDTO(profil);
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see fr.gfi.agraf.service.IProfilService#getAllProfilActif()
	 */
	public List<ProfilDTO> getAllProfil() throws AgrafException {
		// recupere tous les profils
		final List<Profil> profilList = profilDAO.listerTous();
		if (CollectionUtils.isEmpty(profilList)) {
			throw new AgrafException(ERREUR_PROFIL_NOTFOUND);
		}
		// map en DTO et retourne la liste
		return ProfilMapper.entityToDTOList(profilList);
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see
	 * fr.gfi.agraf.service.IProfilService#ajouterProfil(fr.gfi.agraf.service
	 * .beans.ProfilDTO)
	 */
	public void ajouterProfil(final ProfilDTO profilDTO) throws AgrafException {

		// crée l'entité à ajouter en bdd
		final Profil profil = new Profil();
		// verifie si le libelle existe déjà
		final String libelle = profilDTO.getLibelle();
		checkLibelleProfilExist(profil, libelle);
		final Set<Droit> droitSet = ComposantMapper.composantDTOToDroitSet(profilDTO.getListeComposantDTO(),
				profil);
		profil.getSetDroits().addAll(droitSet);
		// ajoute le profil
		profilDAO.persist(profil);
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see fr.gfi.agraf.service.IProfilService#supprimerProfil(java.lang.Long)
	 */
	public void supprimerProfil(final Long id) throws AgrafException {
		// vérifie si des utilisateurs sont encore rattaché au profil
		final List<Utilisateur> checkUtilisateurAttached = utilisateurDAO.getUtilisateursByProfilId(id);
		if (!CollectionUtils.isEmpty(checkUtilisateurAttached)) {
			throw new AgrafException(ERREUR_PROFIL_UTILISATEUR_ATTACHED);
		}
		// supprime le profil
		profilDAO.delete(id);
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see
	 * fr.gfi.agraf.service.IProfilService#modifierProfil(fr.gfi.agraf.vue.bean
	 * .ProfilDTO)
	 */
	public void modifierProfil(final ProfilDTO profilDTO) throws AgrafException {
		final Profil profil = profilDAO.read(profilDTO.getId());
		if (profil == null) {
			throw new AgrafException(ERREUR_PROFIL_NOTFOUND);
		}

		// verifie si un nouveau libelle a été saisi et qu'il est bien different
		// de l'ancien
		if (StringUtils.isNotBlank(profilDTO.getNewLibelle())
				&& !StringUtils.equalsIgnoreCase(profilDTO.getLibelle(), profilDTO.getNewLibelle())) {
			checkLibelleProfilExist(profil, profilDTO.getNewLibelle());
		}
		// efface les anciens composants
		profil.getSetDroits().clear();
		// créé des droits à partir de nouveaux composants
		final Set<Droit> droitSet = ComposantMapper.composantDTOToDroitSet(profilDTO.getListeComposantDTO(),
				profil);
		profil.getSetDroits().addAll(droitSet);
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see
	 * fr.gfi.agraf.service.IProfilService#getAllProfilToModifyUtilisateur(java
	 * .lang.Long)
	 */
	public List<ProfilDTO> getAllProfilToModifyUtilisateur(final Long utilisateurId) throws AgrafException {
		// Récupere tous les profils
		final List<ProfilDTO> allProfils = getAllProfil();
		// Récupere les profils de l'utilisateur à modifier
		final List<ProfilDTO> profilsUtilisateur = getProfilsByUtilisateurID(utilisateurId);
		// Parcour les profils, met à true ceux que l'utilisateur posséde déjà
		for (final ProfilDTO profil : allProfils) {
			if (profilsUtilisateur.contains(profil)) {
				profil.setChecked(true);
			}
			// informations inutiles
			profil.setListeComposantDTO(null);
		}

		return allProfils;
	}

	public List<ProfilDTO> getProfilsByUtilisateurID(final Long utilisateurId) throws AgrafException {
		// récupere les profils
		final List<Profil> profils = profilDAO.getProfilsByUtilisateurId(utilisateurId);
		// convertit en DTO et retourne
		return ProfilMapper.entityToDTOList(profils);
	}

	/**
	 * Verifie si le libelle profil existe en base
	 * 
	 * @param profil
	 * @param libelle
	 * @throws AgrafException
	 */
	private void checkLibelleProfilExist(final Profil profil, final String libelle) throws AgrafException {
		final Profil checkLibelleProfil = profilDAO.getProfilByLibelle(libelle);
		if (checkLibelleProfil == null) {
			profil.setLibelle(libelle);
		} else {
			throw new AgrafException(ERREUR_PROFIL_LIBELLE_EXIST);
		}
	}

	/**
	 * @return the profilDAO
	 */
	public IProfilDAO getProfilDAO() {
		return profilDAO;
	}

	/**
	 * @param profilDAO
	 *            the profilDAO to set
	 */
	public void setProfilDAO(final IProfilDAO profilDAO) {
		this.profilDAO = profilDAO;
	}

	/**
	 * @return the utilisateurDAO
	 */
	public IUtilisateurDAO getUtilisateurDAO() {
		return utilisateurDAO;
	}

	/**
	 * @param utilisateurDAO
	 *            the utilisateurDAO to set
	 */
	public void setUtilisateurDAO(final IUtilisateurDAO utilisateurDAO) {
		this.utilisateurDAO = utilisateurDAO;
	}

}
